//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "helper.h"
#include "cprocess.h"
#include "cthread.h"
#include "tlsmanager.h"
#include <aura.h>

#define TLS_INDEX_EMPTY ((Aura_UInt32)-1)

static IThread * s_pMainThread = NULL;
static IProcess * s_pCurrentProcess = NULL;
static Aura_UInt32 s_currentThreadIndex  = TLS_INDEX_EMPTY;
static Aura_UInt32 s_currentTlsZoneIndex = TLS_INDEX_EMPTY;

static CTlsManager * s_pTlsManager = NULL;
static DLinkNode     s_threadList;

Boolean Helper_Thread_IsMain(
        /* [in] */ IThread * pIThread)
{
    assert(NULL != s_pMainThread);
    return (pIThread == s_pMainThread);
}

IThread * Helper_Thread_GetMain()
{
    assert(NULL != s_pMainThread);
    return s_pMainThread;
}

Boolean Helper_Thread_IsCurrent(
        /* [in] */ IThread * pIThread)
{
    Aura_PVoid pCurThread = NULL;
#if _DEBUG
    assert(s_currentThreadIndex != TLS_INDEX_EMPTY);
    ECode ec =
#endif
    AuraTls_GetValue(s_currentThreadIndex, &pCurThread);
#if _DEBUG
    assert(SUCCEEDED(ec));
#endif

    return (pIThread == static_cast<IThread *>(pCurThread));
}

IThread * Helper_Thread_GetCurrent()
{
    Aura_PVoid pThread = NULL;
#if _DEBUG
    assert(s_currentThreadIndex != TLS_INDEX_EMPTY);
    ECode ec =
#endif
    AuraTls_GetValue(s_currentThreadIndex, &pThread);
#if _DEBUG
    assert(SUCCEEDED(ec));
#endif

    return static_cast<IThread *>(pThread);
}

void Helper_Thread_SetCurrent(
        /* [in] */ IThread * pThread)
{
#if _DEBUG
    assert(s_currentThreadIndex != TLS_INDEX_EMPTY);
    ECode ec =
#endif
    AuraTls_SetValue(s_currentThreadIndex, pThread);
#if _DEBUG
    assert(SUCCEEDED(ec));
#endif
}

IProcess * Helper_Process_GetCurrent()
{
    assert(NULL != s_pCurrentProcess);
    return s_pCurrentProcess;
}

EXTERN ECode InitRunningObjectTable();
EXTERN void DestroyRunningObjectTable();

ECode Helper_PKernel_Initialize()
{
    ECode ec = NOERROR;

    s_pTlsManager = new CTlsManager();
    if (NULL == s_pTlsManager) {
        ec = E_OUT_OF_MEMORY;
        goto E_FAIL_EXIT;
    }
    ec = s_pTlsManager->Constructor();
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = AuraTls_Allocate(&s_currentThreadIndex);
    if (FAILED(ec)) goto E_FAIL_EXIT;
    ec = AuraTls_Allocate(&s_currentTlsZoneIndex);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = CProcess::New(&s_pCurrentProcess);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    ec = CThread::New(&s_pMainThread);
    if (FAILED(ec)) goto E_FAIL_EXIT;

    Helper_Thread_SetCurrent(s_pMainThread);
    s_threadList.Initialize();

    ec = InitRunningObjectTable();
	if (FAILED(ec)) goto E_FAIL_EXIT;

    return NOERROR;

E_FAIL_EXIT:
    Helper_PKernel_Destroy();
    return ec;
}

void Helper_PKernel_Destroy()
{
    if (NULL != s_pMainThread) {
        s_pMainThread->Release();
        s_pMainThread = NULL;
    }
    if (NULL != s_pCurrentProcess) {
        s_pCurrentProcess->Release();
        s_pCurrentProcess = NULL;
    }
    if (TLS_INDEX_EMPTY != s_currentThreadIndex) {
        AuraTls_Free(s_currentThreadIndex);
        s_currentThreadIndex = TLS_INDEX_EMPTY;
    }
    if (TLS_INDEX_EMPTY != s_currentTlsZoneIndex) {
        AuraTls_Free(s_currentTlsZoneIndex);
        s_currentTlsZoneIndex = TLS_INDEX_EMPTY;
    }
    if (NULL != s_pTlsManager) {
        delete s_pTlsManager;
        s_pTlsManager = NULL;
    }
    DestroyRunningObjectTable();

    return ;
}

ECode Helper_TlsMgr_AcquireSlot(
        /* [in] */ ThreadLocalSlotType type,
        /* [out] */ Int32 * pSlotIndex)
{
    return s_pTlsManager->AcquireSlot(type, pSlotIndex);
}

ECode Helper_TlsMgr_RelingquishSlot(
        /* [in] */ Int32 slotIndex,
        /* [out] */ BufferOf<Int32> * pUsedPtrs)
{
    return s_pTlsManager->RelinquishSlot(slotIndex, pUsedPtrs);
}

ECode Helper_TlsMgr_CleanupSlot(
        /* [in] */ Int32 slotIndex,
        /* [out] */ BufferOf<Int32> * pUsedPtrs)
{
    return s_pTlsManager->CleanupSlot(slotIndex, pUsedPtrs);
}

ECode Helper_TlsMgr_GetValue(
        /* [in] */ ThreadLocalSlotType type,
        /* [in] */ Int32 slotIndex,
        /* [out] */ PVoid * ppValue)
{
    return s_pTlsManager->GetSlotValue(type, slotIndex, ppValue);
}

ECode Helper_TlsMgr_SetValue(
        /* [in] */ ThreadLocalSlotType type,
        /* [in] */ Int32 slotIndex,
        /* [in] */ PVoid pValue)
{
    return s_pTlsManager->SetSlotValue(type, slotIndex, pValue);
}


ECode Helper_TlsZone_Create(
        /* [out] */ CTlsZone ** ppTlsZone)
{
    assert(NULL != ppTlsZone);

    CTlsZone * pTlsZone = new CTlsZone();
    if (NULL == pTlsZone) {
        return E_OUT_OF_MEMORY;
    }
    s_pTlsManager->AttachTlsZone(pTlsZone);
    *ppTlsZone = pTlsZone;

    return NOERROR;
}

ECode Helper_TlsZone_Clone(
        /* [in] */ CTlsZone * pTemplate,
        /* [out] */ CTlsZone ** ppTlsZone)
{
    assert(NULL != pTemplate);
    assert(NULL != ppTlsZone);

    CTlsZone * pTlsZone = new CTlsZone(pTemplate);
    if (NULL == pTlsZone) {
        return E_OUT_OF_MEMORY;
    }
    s_pTlsManager->AttachTlsZone(pTlsZone);
    *ppTlsZone = pTlsZone;

    return NOERROR;
}

void Helper_TlsZone_Destroy(
        /* [in] */ CTlsZone * pTlsZone)
{
    assert(NULL != pTlsZone);
    s_pTlsManager->DetachTlsZone(pTlsZone);
    delete pTlsZone;
}

CTlsZone * Helper_TlsZone_GetCurrent()
{
    PVoid pValue = NULL;

#if _DEBUG
    ECode ec =
#endif
    AuraTls_GetValue(s_currentTlsZoneIndex, &pValue);
#if _DEBUG
    assert(SUCCEEDED(ec));
#endif
    return static_cast<CTlsZone *>(pValue);
}

ECode Helper_TlsZone_SetCurrent(
        /* [in] */ CTlsZone * pTlsZone)
{
#if _DEBUG
    ECode ec =
#endif
    AuraTls_SetValue(s_currentTlsZoneIndex, (PVoid)pTlsZone);
#if _DEBUG
    assert(SUCCEEDED(ec));
#endif
    return NOERROR;
}

